package cn.bird.tabledrive;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Supplier;


public class BooleanDriveUtil {
    /**
     * 单参数boolean类型表驱动法
     * boolean 表驱动的特点是，找到第一条满足条件的，即等于true的，返回其内容。
     * 若要使用多参数的，类似于map实现的表驱动法，请使用{@link  MatchUtil}
     */
    public static <T> Optional<T> firstMatch(Function<BooleanDriveBuilder<T>, BooleanDriveBuilder<T>> function) {
        if (Objects.isNull(function)) {
            return Optional.empty();
        }
        return Optional.ofNullable(function.apply(new BooleanDriveBuilder<>())
                .takeResult());
    }

    /**
     * boolean drive 封装实体
     */
    public static class BooleanDriveBuilder<T> {
        protected BooleanDriveBuilder() {
        }
        List<TableDriveBean<T>> tableDriveBeans = new ArrayList<>();

        /**
         * 组装boolean表驱动链
         */
        public BooleanDriveBuilder<T> put(BooleanSupplier booleanCondition, Supplier<T> resultSupplier) {
            if (ObjectUtil.isNull(booleanCondition)) {
                return this;
            }
            this.tableDriveBeans.add(new TableDriveBean<>(booleanCondition, resultSupplier));
            return this;
        }

        /**
         * 组装boolean表驱动链 condition
         */
        public TableDriveBean<T> condition(BooleanSupplier booleanCondition) {
            return new TableDriveBean<>(booleanCondition, this);
        }

        /**
         * 组装boolean表驱动链
         */
        public BooleanDriveBuilder<T> put(BooleanSupplier booleanCondition, T t) {
            return put(booleanCondition, () -> t);
        }

        /**
         * 匹配条件，取第一个匹配的返回
         */
        protected T takeResult() {
            if (CollUtil.isEmpty(this.tableDriveBeans)) {
                return null;
            }
            for (TableDriveBean<T> tTableDriveBean : this.tableDriveBeans) {
                if (tTableDriveBean.getBooleanCondition().getAsBoolean()) {
                    return Optional.ofNullable(tTableDriveBean.getResultSupplier())
                            .map(Supplier::get)
                            .orElse(null);
                }
            }
            return null;
        }
    }


    public static void main(String[] args) {
        BooleanDriveUtil.<String>firstMatch(builder -> builder
                .put(() -> false, "1")
                .put(() -> true, "2")
                .put(() -> true, "3")
        ).ifPresent(System.out::println);

        BooleanDriveUtil.<String>firstMatch(builder -> builder
                .condition(() -> true).result("1")
                .condition(() -> false).result("2")
                .condition(() -> false).result("3")
        ).ifPresent(System.out::println);
    }


}
